/*
 *  Copyright 2008 The MITRE Corporation (http://www.mitre.org/). All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.mitre.lattice.graph;

import org.mitre.mrald.util.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.mitre.lattice.lattice.InsufficentGroupAccessException;
import org.mitre.lattice.lattice.InvalidLatticeStructureException;
import org.mitre.lattice.lattice.LatticeElement;
import org.mitre.lattice.lattice.LatticeErrorHandler;
import org.mitre.lattice.lattice.LatticeException;
import org.mitre.lattice.lattice.LatticeFunctions;
import org.mitre.lattice.lattice.LatticeNode;
import org.mitre.lattice.lattice.LatticeTree;
import org.mitre.lattice.lattice.LatticeUserGroup;
import org.mitre.lattice.lattice.MultipleParentsException;
import org.mitre.lattice.lattice.NodeNotFoundException;
import org.mitre.mrald.control.AbstractStep;
import org.mitre.mrald.control.MsgObject;
import org.mitre.mrald.control.MsgObjectException;
import org.mitre.mrald.control.WorkflowStepException;
import org.mitre.mrald.util.Config;
import org.mitre.mrald.util.FileUtils;
import org.mitre.mrald.util.FormTags;
import org.mitre.mrald.util.MiscUtils;
import org.mitre.mrald.util.MraldConnection;
import org.mitre.mrald.util.MraldException;
import org.mitre.mrald.util.User;
/**
 *  This function is a wrapper class for graphing the Users Lattice. Based on a
 *  login.
 *
 *@author     ghamilton
 *@created    November 12, 2003
 */
public class GraphUserLattice extends AbstractStep
{

    /**
     *  Description of the Field
     */
    public final static String KEY = GraphUserLattice.class.getName();
    /**
     *  Description of the Field
     */
    public final static Logger log = Logger.getLogger(KEY);
    static { log.setLevel(Level.FINEST); }

    private LatticeException latticeErr = null;
    private String keyGroup = null;
    private String[] userGroups = null;

    private static LatticeTree lattice = null;


    /**
     *  Constructor for the GraphUserLattice object
     */
    public GraphUserLattice()
    {
        try
        {
				//MraldOutFile.logToFile( Config.getProperty("LOGFILE") , "GraphUserLattice: Start " );


        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }


    /**
     *  Description of the Method
     *
     *@param  msg                                                Description of the
     *      Parameter
     *@exception  org.mitre.mrald.control.WorkflowStepException  Description of the
     *      Exception
     *@exception  MraldException                                 Description of the
     *      Exception
     */
    public void graphLatticeNonGeneric(MsgObject msg) throws org.mitre.mrald.control.WorkflowStepException, MraldException
    {
        try
        {
            LatticeFunctions.setImplmnt();

            String[] showLattice = msg.getValue("showLattice");
            boolean showWholeLattice = true;

            if (showLattice[0].equals(""))
            {
                showWholeLattice = false;
            }

//            MinimizingDistance minDistance = new MinimizingDistance();

            //LatticeTree newLattice = SampleLattices.buildVeryVeryComplexDiamondLattice();
            LatticeTree newLattice = (LatticeTree) getLattice();

            LatticeTree childTree = null;

            HttpServletRequest req = msg.getReq();
            HttpSession ses = req.getSession();
            LatticeUserGroup userGroup = null;
            User user = null;
            if (ses == null)
            {
                HttpServletResponse resp = msg.getRes();

                resp.sendRedirect(Config.getProperty("BaseUrl") + "/LatticeLogin.jsp?pageurl=" + req.getRequestURL());
                return;
            } else
            {
                user = (User) ses.getAttribute(Config.getProperty("cookietag"));
                userGroup = new LatticeUserGroup(user.getGroup());
            }
            //If any parents or child groups to be added
            //Then this has to happen before the Lattice is drawn.
            //The key Node will be the newly added Node

            //Make sure that the Child objects are added first.
            //As the newly created node will be found from recursively
            //moving upwards from the root node.
            //i.e. By recursively getting the parents foe each node.

            ArrayList latticeElements = msg.getWorkingObjects();

            //
            //User user = (User) pageContext.getAttribute(Config.getProperty("cookietag"), pageContext.SESSION_SCOPE);

            try
            {
                keyGroup = user.getGroup();
            } catch (NullPointerException e)
            {
                //In this case force the user to login

                //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "Group List Tag: doStartTag. About to login.");

                //HttpServletResponse resp = msg.getRes();
                //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "VGroup List Tag: doStartTag. About to redirect.");
                //resp.sendRedirect(Config.getProperty("BaseUrl") + "/LatticeLogin.jsp?pageurl=" + req.getRequestURL());
            }

            newLattice = (LatticeTree) processElements(latticeElements, newLattice);

            if (!keyGroup.equals(""))
            {

                userGroup.setUserGroups(userGroups);

                String keyNodeStr = userGroup.getMostDominant(newLattice.getRootNode());

                LatticeNode key = newLattice.searchTree(keyNodeStr);

                if (!showWholeLattice)
                {
                    if (key != newLattice.getRootNode())
                    {
                        childTree = new LatticeTree((LatticeNode) LatticeFunctions.getChildTree(key));

                        if ((childTree == null) || (childTree.getRootNode() == null))
                        {
                            throw new InsufficentGroupAccessException("You have insufficent privilidges to access this system. Please contact your system Administrator..");
                        }
                    } else
                    {
                        childTree = new LatticeTree(Config.getLatticeFactory().copyNode(key));
                    }

                    //minDistance.setLatticeTree(childTree);
                } else
                {
                    //Make sure that all the attributes are synchronized

                    //minDistance.setLatticeTree(newLattice);
                }

                //Object[] solnPoints = minDistance.calcDistance();

                GraphLattice newGraph = new GraphLattice();

                //gh newGraph.graphSolution((Object[]) solnPoints[0], (Object[]) solnPoints[1]);

                newGraph.graphSolution();

                GraphLattice.createImageFile(GraphLattice.getGraph(), user);

                //Pass in the keyNode value to be used to filter the
                //groups that are displayed in the AddNode.jsp
                String output = GraphLattice.convertToHtml(GraphLattice.getGraph(), Config.getProperty("latticeGraph"), showLattice[0], user);

                outputHtml(msg, output);

                storeLattice(newLattice);
            } else
            {
                //MraldOutFile.logToFile( Config.getProperty("LOGFILE"), "No groups found");

                latticeErr = new InsufficentGroupAccessException("LATT-003");
            }
        } catch (LatticeException e)
        {
            latticeErr = e;
        } catch (ServletException e)
        {
            throw new WorkflowStepException(e);
        } catch (IOException e)
        {
            throw new WorkflowStepException(e);
        } catch (MsgObjectException e)
        {
            throw new WorkflowStepException(e);
        } catch (Exception e)
        {
            throw new WorkflowStepException(e);
        }
    }


    /**
     *  Description of the Method
     *
     *@param  msg                                                Description of the
     *      Parameter
     *@exception  org.mitre.mrald.control.WorkflowStepException  Description of the
     *      Exception
     *@exception  MraldException                                 Description of the
     *      Exception
     */
    public void graphLattice(MsgObject msg) throws org.mitre.mrald.control.WorkflowStepException, MraldException
    {

	    try //Check to see if the Lattice Security has been enabled
	    {
		    if (!Config.getLatticeFactory().getUsingLatticeSecurityModel())
			    latticeErr = new LatticeException("The Lattice Security Model is currently disabled. Please contact your system Administrator if you require Lattice Security to be enabled. ");

	    }
	    catch (LatticeException e)
	    {
		    latticeErr = e;
		    throw e;
	    }

        try
        {

            log.entering(KEY, "graphLattice(MsgObject)");
            LatticeFunctions.setImplmnt();

            String[] showLattice = msg.getValue("showLattice");
            boolean showWholeLattice = true;

            if (showLattice[0].equals(""))
            {
                showWholeLattice = false;
            }
            log.finest( "About to start MinimizingDistance" );
 //           MinimizingDistance minDistance = new MinimizingDistance();

            //LatticeTree newLattice = SampleLattices.buildVeryVeryComplexDiamondLattice();
            LatticeTree newLattice = (LatticeTree) getLattice();
            log.finest( "Lattice retrieved" );
            LatticeTree childTree = null;

            HttpServletRequest req = msg.getReq();
            HttpSession ses = req.getSession();
            LatticeUserGroup userGroup = null;
            User user = null;
            if (ses == null)
            {
                HttpServletResponse resp = msg.getRes();

                resp.sendRedirect(Config.getProperty("BaseUrl") + "/LatticeLogin.jsp?pageurl=" + req.getRequestURL());
                return;
            } else
            {
                user = (User) ses.getAttribute(Config.getProperty("cookietag"));
                userGroup = new LatticeUserGroup(user.getGroup());
            }
            //If any parents or child groups to be added
            //Then this has to happen before the Lattice is drawn.
            //The key Node will be the newly added Node

            //Make sure that the Child objects are added first.
            //As the newly created node will be found from recursively
            //moving upwards from the root node.
            //i.e. By recursively getting the parents foe each node.

            ArrayList latticeElements = msg.getWorkingObjects();

            //
            //User user = (User) pageContext.getAttribute(Config.getProperty("cookietag"), pageContext.SESSION_SCOPE);

            try
            {
                keyGroup = user.getGroup();

            } catch (NullPointerException e)
            {
                //In this case force the user to login

                //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "Group List Tag: doStartTag. About to login.");

                //HttpServletResponse resp = msg.getRes();
                //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "VGroup List Tag: doStartTag. About to redirect.");
                //resp.sendRedirect(Config.getProperty("BaseUrl") + "/LatticeLogin.jsp?pageurl=" + req.getRequestURL());
            }
            log.finest("About to process elements (add, delete, etc.");

            newLattice = (LatticeTree) processElements(latticeElements, newLattice);
            if (!keyGroup.equals(""))
            {
                log.finest("COI assigned: " + keyGroup);
                userGroup.setUserGroups(userGroups);

                //Get the most dominant of the Users groups that they are assigned to.
                String keyNodeStr = userGroup.getMostDominant(newLattice.getRootNode());

                LatticeNode key = newLattice.searchTree(keyNodeStr);

                if (!showWholeLattice)
                {

                    if (key != newLattice.getRootNode())
                    {
                        childTree = new LatticeTree((LatticeNode) LatticeFunctions.getChildTree(key));

                        if ((childTree == null) || (childTree.getRootNode() == null))
                        {
                            throw new InsufficentGroupAccessException("You have insufficent privilidges to access this system. Please contact your system Administrator..");
                        }
                    } else
                    {
                        childTree = new LatticeTree(Config.getLatticeFactory().copyNode(key));
                    }

                    childTree = new LatticeTree((LatticeNode) LatticeFunctions.getSubTree(childTree, newLattice.getRootNode()));

                    MinimizingDistance.setLatticeTree(childTree);
                } else
                {
                    //Make sure that all the attributes are synchronized

                    MinimizingDistance.setLatticeTree(newLattice);
                }
                Object[] solnPoints = MinimizingDistance.calcDistance();
                log.finest("About to creat Graph Lattice");
                GraphLattice newGraph = new GraphLattice();
                log.finest("Success: created GraphLattice");
                newGraph.graphSolution((Object[]) solnPoints[0], (Object[]) solnPoints[1]);
                //newGraph.graphSolution();
                log.finest("Dumping a new image file");
                GraphLattice.createImageFile(GraphLattice.getGraph(), user);

                //Pass in the keyNode value to be used to filter the
                //groups that are displayed in the AddNode.jsp
                String output = GraphLattice.convertToHtml(GraphLattice.getGraph(), Config.getProperty("latticeGraph"), showLattice[0], user);
                log.finest("sending HTML to the client");
                outputHtml(msg, output);
            } else
            {
		      if (Config.usingSecurity )
		      {

			       //MraldOutFile.logToFile( Config.getProperty("LOGFILE"), "No groups found");
			    log.finest("No COI assigned - need to go log in");
			    latticeErr = new InsufficentGroupAccessException("LATT-003: You have insufficent privilidges to access this system. Please contact your system Administrator..");

		      }
		      else
		      {

			         latticeErr = new LatticeException("Lattice Security cannot be enabled with Log In Security turned off. Please contact your system Administrator if you wish to have Lattice Security feature enabled. ");
		      }
            }
            log.exiting(KEY, "graphLattice(MsgObject)");
        } catch (LatticeException e)
        {
            latticeErr = e;
        } catch (ServletException e)
        {
            throw new WorkflowStepException(e);
        } catch (IOException e)
        {
            throw new WorkflowStepException(e);
        } catch (MsgObjectException e)
        {
            throw new WorkflowStepException(e);
        } catch (Exception e)
        {
            throw new WorkflowStepException(e);
        }
    }

    /**
     *  This method prepares the output file for the HTML format data
     *
     *@return                     The lattice value
     *@exception  MraldException  Description of the Exception
     *@since
     */
    public static void resetLattice()
         throws MraldException
    {
	    lattice = null;
    }
    /**
     *  This method prepares the output file for the HTML format data
     *
     *@return                     The lattice value
     *@exception  MraldException  Description of the Exception
     *@since
     */
    public static Object getLattice()
         throws MraldException
    {
        try
        {

            log.info("Checking to see if the lattice tree file is null");

            if (lattice == null)
            {
                String fileName = Config.getProperty("LatticeFile");

                log.info("About to get the lattice tree file");
                lattice = LatticeFunctions.recoverLatticeTree(fileName);

                if (lattice != null)
                {
                    log.info("Got old lattice file");
                    return lattice;
                } else
                {
                    log.info("Got completely new lattice file");
                    return SampleLattices.buildNewLattice();
                }
            }
            log.info("Returning the Lattice Tree from memory");

            return lattice;
        } catch (FileNotFoundException e)
        {
            log.log(Level.INFO, "Serialized lattice file wasn't found.  The lattice file is being blow away.", e);
            //If the file isn't found then create a new file
            return SampleLattices.buildNewLattice();
        } catch (IOException e)
        {
            log.log(Level.INFO, "Other IO problem.  The lattice file is being blow away.", e);
            //If the file isn't found then create a new file
            return SampleLattices.buildNewLattice();
        }
    }


    /**
     *  This method prepares the output file for the HTML format data
     *
     *@param  lattice             Description of the Parameter
     *@exception  MraldException  Description of the Exception
     *@since
     */
    public static void storeLattice(Object lattice)
         throws MraldException
    {
        try
        {
            String filename = Config.getProperty("LatticeFile");
	     String latticeDir = filename.substring(0, filename.lastIndexOf("/"));


	    if (!new File(latticeDir).exists())
	    {
			boolean created = new File(latticeDir).mkdirs();
			if (!created)
			{
				throw new IOException("Couldn't create the directory \"" + latticeDir +
					"\".  Check your file system, though, some intermediate directories may have been created");
			}
	    }

            if (!new File(filename).exists())
            {
                boolean created = new File(Config.getProperty("LatticeFile")).createNewFile();

                if (!created)
                {
                    throw new IOException("Couldn't create the directory \"" + Config.getProperty("LatticeFile") +
                        "\".  Check your file system, though, some intermediate directories may have been created");
                }
            }
            backupLattice(filename);

            //Temp
            //LatticeTree wrappedTree = LatticeFunctions.wrapTree( (LatticeTree)lattice) ;
            //LatticeFunctions.serializeLatticeTree( wrappedTree, filename );
            //Temp end

            LatticeFunctions.serializeLatticeTree((LatticeTree) lattice, filename);


        } catch (IOException ioe)
        {
            throw new MraldException(ioe.getMessage());
        }

    }


    /**
     *  This method prepares the output file for the HTML format data
     *
     *@param  filename            Description of the Parameter
     *@exception  MraldException  Description of the Exception
     *@since
     */
    public static void backupLattice(String filename)
         throws MraldException
    {
        try
        {

            //Store the last version under LatticeDir/backup/Recent/lattice.srv

            String latticeFile = Config.getProperty("LatticeFile");
            String fileName = latticeFile.substring(latticeFile.lastIndexOf("/"));
            String latticeDir = latticeFile.substring(0, latticeFile.lastIndexOf("/"));

            String backupDir = latticeDir + "/backup/last";
            FileUtils fileUtils = new FileUtils();

            fileUtils.backupFile(latticeFile, backupDir + "/" + fileName);

            //Get todays date, and use
            Calendar now = Calendar.getInstance();
            int month = new Integer(now.get(Calendar.MONTH)).intValue() + 1;
            String dateDirectory = month + "_" + now.get(Calendar.DAY_OF_MONTH) + "_" + now.get(Calendar.YEAR);
            dateDirectory = latticeDir + "/backup/" + dateDirectory;

            //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "Graph User Lattice. DateDirectory " + dateDirectory);

            fileUtils.backupFile(latticeFile, dateDirectory + "/" + fileName);

        } catch (Exception e)
        {
            throw new MraldException(e.getMessage());
        }

    }


    /**
     *  This method prepares the output file for the HTML format data
     *
     *@param  deleteNodes                           Description of the Parameter
     *@param  lattice                               Description of the Parameter
     *@return                                       Description of the Return Value
     *@exception  NodeNotFoundException             Description of the Exception
     *@exception  LatticeException                  Description of the Exception
     *@exception  MultipleParentsException          Description of the Exception
     *@exception  InvalidLatticeStructureException  Description of the Exception
     *@since
     */
    public static Object deleteNode(ArrayList deleteNodes, Object lattice)
         throws NodeNotFoundException, LatticeException, MultipleParentsException, InvalidLatticeStructureException
    {
        if (deleteNodes.size() == 0)
        {
            return lattice;
        }

        LatticeElement elem = (LatticeElement) deleteNodes.get(0);
        MsgObject deleteMsg = elem.getNameValues();
        String[] deleteParents = deleteMsg.getValue("deleteGroup");

        for (int i = 0; i < deleteParents.length; i++)
        {
            String parentStr = deleteParents[i];

            LatticeNode deleteNode = ((LatticeTree) lattice).searchTree(parentStr);

            //Get Parent, remove from it's children

            ArrayList parents = deleteNode.getParents();

            if (parents.size() > 1)
            {
                throw new MultipleParentsException("LATT-001");
            }
            //throw new MultipleParentsException( "You may only delete a node if you are the only remaining parent group. Please delete all additional Parent groups first.");

            for (int j = 0; j < parents.size(); j++)
            {
                LatticeNode parent = (LatticeNode) parents.get(j);
                parent.removeChild(deleteNode);

                //Reassign the Parents of the node to be deleted to
                //all the Children

                parent.reAssignChild(deleteNode);

            }
            //Get Children. Remove itself from the child Parents
            ArrayList children = deleteNode.getChildren();

            for (int k = 0; k < children.size(); k++)
            {
                LatticeNode child = (LatticeNode) children.get(k);

                child.removeParent(deleteNode);

            }
            //Set the node to null
            deleteNode = null;
        }
        return lattice;
    }


    /**
     *  This method prepares the output file for the HTML format data
     *
     *@param  latticeElements                       Description of the Parameter
     *@param  lattice                               Description of the Parameter
     *@return                                       Description of the Return Value
     *@exception  NodeNotFoundException             Description of the Exception
     *@exception  InvalidLatticeStructureException  Description of the Exception
     *@exception  LatticeException                  Description of the Exception
     *@exception  MraldException                    Description of the Exception
     *@since
     */
    public Object processElements(ArrayList latticeElements, Object lattice)
         throws NodeNotFoundException, InvalidLatticeStructureException, LatticeException, MraldException
    {
	    		//MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "GraphUserLattice: ProcessElements. Start " );

        LatticeTree newLattice = (LatticeTree) lattice;
        ArrayList<LatticeElement> viewElements = new ArrayList<LatticeElement>();
        ArrayList<LatticeElement> addElements = new ArrayList<LatticeElement>();
        ArrayList<LatticeElement> deleteElements = new ArrayList<LatticeElement>();
        ArrayList<LatticeElement> deleteLinkElements = new ArrayList<LatticeElement>();

        for (int i = 0; i < latticeElements.size(); i++)
        {
            LatticeElement latticeElem = (LatticeElement) latticeElements.get(i);
            String type = (latticeElem.getNameValues().getValue("Type"))[0];

            if (type.equals("Add"))
            {

		//MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "GraphUserLattice: Adding Node " + latticeElem.getType() );

                addElements.add(latticeElem);
            } else if (type.equals("Delete"))
            {
                deleteElements.add(latticeElem);
            } else if (type.equals("DeleteLink"))
            {
                deleteLinkElements.add(latticeElem);
            } else if (type.equals("securityGroup"))
            {
                //These are the element sfor viewing
                viewElements.add(latticeElem);
            } else
            {
                //If no type is specified then this is a text entry. Which
                //only exists for Adding a new Node
                addElements.add(latticeElem);
            }
        }
        newLattice = (LatticeTree) addNode(addElements, newLattice);
        newLattice = (LatticeTree) deleteNode(deleteElements, newLattice);
        newLattice = (LatticeTree) deleteLink(deleteLinkElements, newLattice);

        keyGroup = getKeyGroup(viewElements);
        log.finest("Storing the lattice file");
        storeLattice(newLattice);

        return newLattice;
    }


    /**
     *  Gets the keyGroup attribute of the GraphUserLattice object
     *
     *@param  viewElements  Description of the Parameter
     *@return               The keyGroup value
     */
    public String getKeyGroup(ArrayList viewElements)
    {

        for (int i = 0; i < viewElements.size(); i++)
        {
            LatticeElement lattElem = (LatticeElement) viewElements.get(i);
            userGroups = lattElem.getNameValues().getValue("securityGroup");
        }

        //If not UserGroups found then just send back the one set.

        if (userGroups == null)
        {
            userGroups = new String[]{keyGroup};
            return keyGroup;
        }
        if (userGroups.length > 0)
        {
            keyGroup = userGroups[0];
        }

        return keyGroup;
    }


    /**
     *  This method prepares the output file for the HTML format data
     *
     *@param  deleteLinks                           Description of the Parameter
     *@param  lattice                               Description of the Parameter
     *@return                                       Description of the Return Value
     *@exception  NodeNotFoundException             Description of the Exception
     *@exception  InvalidLatticeStructureException  Description of the Exception
     *@since
     */
    public static Object deleteLink(ArrayList deleteLinks, Object lattice)
         throws NodeNotFoundException, InvalidLatticeStructureException
    {

        MsgObject deleteMsg = null;
        LatticeTree latticeTree = (LatticeTree) lattice;

        if (latticeTree.getRootNode().equals(latticeTree.searchTree("Public")))
        {
            //MraldOutFile.logToFile( Config.getProperty("LOGFILE") , "GraphUserLattice. DeleteLink: Root node and Public are equal");
        } else
        {
            //MraldOutFile.logToFile( Config.getProperty("LOGFILE") , "GraphUserLattice. DeleteLink: Root node and Public are NOT equal");
        }

        for (int i = 0; i < deleteLinks.size(); i++)
        {

            LatticeElement latticeElem = (LatticeElement) deleteLinks.get(i);

            deleteMsg = latticeElem.getNameValues();

            String parent = deleteMsg.getValue("Parent")[0];

            LatticeNode deleteNode = latticeTree.searchTree(parent);

            String childName = deleteMsg.getValue("Child")[0];

            LatticeNode child = latticeTree.searchTree(childName);

            //If this child node, is the last link to Public, then do not allow deletion
            //instead make the User delete the node

            if (child.equals(latticeTree.getRootNode()))
            {
                throw new InvalidLatticeStructureException("LATT-006", "");
            }

            child.getParents().remove(deleteNode);

            if (!deleteNode.reAssignChild(child))
            {

                deleteNode.reAssignParentsToPublic(latticeTree.getRootNode());
            }
        }
        return lattice;
    }



    /**
     *  This method prepares the output file for the HTML format data
     *
     *@param  addNodes                              The feature to be added to the
     *      Node attribute
     *@param  lattice                               The feature to be added to the
     *      Node attribute
     *@return                                       Description of the Return Value
     *@exception  NodeNotFoundException             Description of the Exception
     *@exception  InvalidLatticeStructureException  Description of the Exception
     *@exception  MraldException                    Description of the Exception
     *@since
     */
    public Object addNode(ArrayList addNodes, Object lattice)
         throws NodeNotFoundException, InvalidLatticeStructureException, MraldException
    {

	//MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "GraphUserLattice: In addNodes: Start " );
        if (addNodes.size() == 0)
        {
            return lattice;
        }

	//MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "GraphUserLattice: In addNodes: Size: "  + addNodes.size());

        boolean childAdded = false;
        boolean parentAdded = false;
        boolean isNewNode = true;

        LatticeNode newNode = null;
        LatticeTree latticeTree = ((LatticeTree) lattice);
        LatticeElement elem = (LatticeElement) addNodes.get(0);
        MsgObject addMsg = elem.getNameValues();
        String newNodeName = addMsg.getValue(FormTags.VALUE_TAG)[0];

        //If the user did not input a value, then they selected it frm the drop down list
        if (newNodeName == "")
        {
            newNodeName = addMsg.getValue("addNode")[0];
        }
        try
        {
            newNode = latticeTree.searchTree(newNodeName);
            isNewNode = false;
        } catch (NodeNotFoundException e)
        {
            newNode = Config.getLatticeFactory().createNode(newNodeName);

            log.info(" Node creation here : " + newNodeName + " no type ");

            //If any customizable attributes to be set. THis function will set them
            newNode = setCustomizable(addMsg, newNode);
            //As this is a new node. Add Public as the default. SInce no children have been
            //specified.


        }

        String[] children = addMsg.getValue("Child");

        //Get the nodes represented by the Child Node names
        //Create a new Node, to be the keyNode
        //change the lattice

        //First check if adding any of the nodes would throw the
        //Lattice into an inconsistent state.


        for (int i = 0; i < children.length; i++)
        {

	     //String childName = MiscUtils.checkApostrophe(children[i]);
	    String childName = children[i];

            if (!childName.equals(""))
            {
                LatticeNode childKey = latticeTree.searchTree(childName);

                //If the parent is added successfully, then add the Child
                if (childKey.addParent(newNode))
                {
                    childAdded = newNode.addChild(childKey);
                }

                if (childAdded)
                {
                    latticeTree.removeCyclic(childKey, newNode);
                }
            }
        }

        //If no Child node is specified then do the default. i.e. Add as parent to the root node.
        if (!childAdded && isNewNode)
        {
            LatticeNode childKey = latticeTree.searchTree("Public");

            if (childKey.addParent(newNode))
            {
                childAdded = newNode.addChild(childKey);
            }

            if (childAdded)
            {
                latticeTree.removeCyclic(childKey, newNode);
            }
        }

        String[] addParents = addMsg.getValue("Parent");

        for (int i = 0; i < addParents.length; i++)
        {
            //MraldOutFile.logToFile( Config.getProperty("LOGFILE") , "GraphUserLattice : in Add node: About to add a parent : "+ addParents[i] + " to new Node " + newNodeName );

	    //String parentName = MiscUtils.checkApostrophe(addParents[i]);

	    String parentName =addParents[i];

	    //MraldOutFile.logToFile( Config.getProperty("LOGFILE") , "GraphUserLattice : in Add node: About to add a parent : "+ parentName + " to new Node " + newNodeName );

            if (!parentName.equals(""))
            {
                LatticeNode parentKey = latticeTree.searchTree(parentName);

                if (parentKey.addChild(newNode))
                {
                    parentAdded = newNode.addParent(parentKey);
                }

                if (parentAdded)
                {
                    latticeTree.removeCyclicChild(parentKey, newNode);
                }
            }
        }

        //Check if this lattice exists within the lattice group table
        //if it doesn't then add
        addToLatticeGroups(new String[]{newNodeName});

        return latticeTree;
    }


    /**
     *  This method prepares the output file for the HTML format data
     *
     *@param  newNodes            The feature to be added to the ToLatticeGroups
     *      attribute
     *@exception  MraldException  Description of the Exception
     *@since
     */
    public static void addToLatticeGroups(String[] newNodes)
         throws MraldException
    {
        try
        {
            //Create a connection object
            MraldConnection conn = new MraldConnection( MetaData.ADMIN_DB );

            String selectStr = "select latticegroupid from latticegroup ";
            ResultSet rs = conn.executeQuery(selectStr);

            ArrayList<String> cois = new ArrayList<String>();

            while (rs.next())
            {
                cois.add(rs.getString(1));
            }

            String updateStatement = "INSERT INTO latticegroup values( '<:groupid:>', '<:groupName:>', '')";

            for (int i = 0; i < newNodes.length; i++)
            {
                //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "GraphUserLattice : in Add node: About to add a parent : " + newNodes[i]);

                if (!newNodes[i].equals(""))
                {
                    if (!cois.contains(newNodes[i]))
                    {
			//If using 'replace' need to call MiscUtils.checkWHiteSpace twice-
			String coi = MiscUtils.checkApostrophe(MiscUtils.checkApostrophe(newNodes[i]));

                        updateStatement = updateStatement.replaceAll("<:groupid:>", coi);
                        updateStatement = updateStatement.replaceAll("<:groupName:>", coi);

                        //add to the list of update statements

                        //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "GraphUserLattice : in Add node: About to execute update to database  : " + updateStatement);

                        conn.executeUpdate(updateStatement);
                    }
                }
            }

            conn.close();

        } catch (Exception e)
        {
            MraldException me = new MraldException(e.getMessage());
            throw me;
        }
    }


    /**
     *  This method prepares the output file for the HTML format data
     *
     *@param  msg                     Description of the Parameter
     *@param  output                  Description of the Parameter
     *@exception  ServletException    Description of the Exception
     *@exception  IOException         Description of the Exception
     *@exception  MsgObjectException  Description of the Exception
     *@since
     */
    public static void outputHtml(MsgObject msg, String output)
         throws ServletException, IOException, MsgObjectException
    {
        /*
         *  msg.SetOutPrintWriter();
         *  msg.setContentType( "text/html" );
         *  msg.setHeader( "Content-Disposition", "inline;" );
         *  msg.setHeader( "Content-Disposition", "inline;" );
         *  /msg.setHeader( "Refresh", "2" );
         *  PrintWriter out = msg.getOutPrintWriter();
         */
        HttpServletResponse res = msg.getRes();
        res.sendRedirect(Config.getProperty("BaseUrl") + "/LatticeManagement.jsp");

        //java.io.OutputStream out = msg.getOutStreamWriter();
        //out.write(output);


        /*
         *  out.print( output);
         *  out.flush();
         *  out.close();
         */
    }


    /**
     *@param  args  the command-line arguments.
     */
    public static void main(String[] args)
    {

        try
        {
            //graphLattice();

        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }


    /**
     *  Description of the Method
     *
     *@param  msg                        Description of the Parameter
     *@exception  WorkflowStepException  Description of the Exception
     */
    public void execute(MsgObject msg) throws WorkflowStepException
    {
        try
        {
            graphLattice(msg);
            //For User exceptions. Display the error message.
            if (latticeErr != null)
            {
                LatticeErrorHandler.handleException(msg, latticeErr, true);
            }
        } catch (Exception e)
        {
            throw new WorkflowStepException(e);
        }

    }


    /**
     *  If there are any customizable attributes to be set Then these should be set
     *  in this method in the inherited class.
     *
     *@param  msg      The new customizable value
     *@param  newNode  The new customizable value
     *@return          Description of the Return Value
     *@since
     */
    public LatticeNode setCustomizable(MsgObject msg, LatticeNode newNode)
    {
        log.info("Node type is: None ");

        return newNode;
    }

}

